package pe.com.casadesign.dao.impl;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcCall;
import org.springframework.stereotype.Repository;

import pe.com.casadesign.dao.UsuarioDAO;
import pe.com.casadesign.domain.ListaModulo;
import pe.com.casadesign.domain.ListaRol;
import pe.com.casadesign.domain.ListaUsuario;
import pe.com.casadesign.domain.Modulo;
import pe.com.casadesign.domain.Rol;
import pe.com.casadesign.domain.Usuario;

/**
 * Implementacion de UsuarioDAO.
 * 
 * @author Pedro Vera
 * 
 */
@Repository
public class UsuarioDAOImpl implements UsuarioDAO {
	private static final Logger logger = LoggerFactory.getLogger(UsuarioDAOImpl.class);
	
	// Nombre Procedimientos Almacenados
	private static String SP_LISTAR_USUARIO = "SP_LISTAR_USUARIO";
	private static String SP_OBTENER_USUARIO = "SP_OBTENER_USUARIO";
	private static String SP_VALIDAR_USUARIO = "SP_VALIDAR_USUARIO";
	private static String SP_REGISTRAR_USUARIO = "SP_REGISTRAR_USUARIO";
	private static String SP_MODIFICAR_USUARIO = "SP_MODIFICAR_USUARIO";
	private static String SP_ELIMINAR_USUARIO = "SP_ELIMINAR_USUARIO";
	
	private static String SP_LISTAR_ROL = "SP_LISTAR_ROL";
	private static String SP_CONSULTAR_ROL_MODULO = "SP_CONSULTAR_ROL_MODULO";
	
	// Parametros de Entrada
	private static String PARAM_CODUSUARIO = "p_codusuario";
	private static String PARAM_NOMBRES = "p_nombres";
	private static String PARAM_APELLIDOS = "p_apellidos";
	private static String PARAM_NOMUSER = "p_nomuser";
	private static String PARAM_PASSUSER = "p_passuser";
	private static String PARAM_ESTADO = "p_estado";
	private static String PARAM_CODROL = "p_codrol";
	private static String PARAM_CODMODULO = "p_codmodulo";
	private static String PARAM_EMAIL = "p_email";
	
	// Parametros de Salida
	private static String CODUSUARIO = "CODUSUARIO";
	private static String NOMBRES = "NOMBRES";
	private static String APELLIDOS = "APELLIDOS";
	private static String NOMBRESYAPELLIDOS = "NOMBRESYAPELLIDOS";
	private static String NOMUSER = "NOMUSER";
	private static String PASSUSER = "PASSUSER";
	private static String ESTADO = "ESTADO";
	private static String FECHAREGISTRO = "FECHAREGISTRO";
	private static String EMAIL = "EMAIL";
	
	private static String MODULO_CODMODULO = "CODMODULO";
	private static String MODULO_DESCRIPCION = "DESCRIPCION";
	//private static String MODULO_ESTADO = "ESTADO";
	//private static String MODULO_FECHAREGISTRO = "FECHAREGISTRO";
	
	private static String ROL_CODROL = "CODROL";
	private static String ROL_DESCRIPCION = "DESCRIPCION";
	private static String ROL_ESTADO = "ESTADO";
	
	private static String ROL_HABILITADO = "HABILITADO";
	//private static String ROL_FECHAREGISTRO = "FECHAREGISTRO";
	
	private static String LISTADO = "LISTADO";
	
	private static String LISTADO_MODULOS = "LISTADO_MODULOS";
	
	private static String TOTAL_FILAS_AFECTADAS = "#update-count-1";
	
	private JdbcTemplate jdbcTemplate;

	@Autowired
    public void setDataSource(DataSource dataSource)
    {
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }

	@Override
	public Usuario validarUsuario(Usuario usuario) {
		logger.info("validarUsuario");
		
		// Instanciando variable para llamado de SP
	    SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_VALIDAR_USUARIO).
								  returningResultSet(LISTADO, new RowMapper<Usuario>(){
									@Override
									public Usuario mapRow(final ResultSet rs, final int numRow) throws SQLException
								    {
								        final Usuario usuario = new Usuario();
								        usuario.setCodUsuario(rs.getInt(CODUSUARIO));
								        usuario.setNombres(rs.getString(NOMBRES));
								        usuario.setApellidos(rs.getString(APELLIDOS));
								        usuario.setNombresyApellidos(rs.getString(NOMBRESYAPELLIDOS));
								        usuario.setNomUser(rs.getString(NOMUSER));
								        usuario.setPassUser(rs.getString(PASSUSER));
								        usuario.setEstado(rs.getString(ESTADO));
								        usuario.setEmail(rs.getString(EMAIL));
								        
								        Rol rol = new Rol();
								        rol.setCodigo(rs.getInt(ROL_CODROL));
								        
								        usuario.setRol(rol);
								        
								        usuario.setFechaRegistro(rs.getDate(FECHAREGISTRO).toString());
								        return usuario;
								    }
								  }
								 ).
								 returningResultSet(LISTADO_MODULOS, new RowMapper<Modulo>(){
										@Override
										public Modulo mapRow(final ResultSet rs, final int numRow) throws SQLException
									    {
									        final Modulo modulo = new Modulo();
									        modulo.setCodigo(rs.getInt(MODULO_CODMODULO));
									        modulo.setDescripcion(rs.getString(MODULO_DESCRIPCION));
									        //modulo.setEstado(rs.getString(MODULO_ESTADO));
									        //modulo.setFechaRegistro(rs.getDate(MODULO_FECHAREGISTRO).toString());
									        return modulo;
									    }
									  }
								);

	    // Estableciendo parametros de entrada al SP
	    SqlParameterSource parametros = new MapSqlParameterSource()
	    								.addValue(PARAM_NOMUSER, usuario.getNomUser())
	    								.addValue(PARAM_PASSUSER, usuario.getPassUser());

	    // Establecer parametros y ejecutar SP
        Map<String,Object> data = llamarSP.execute(parametros);

        // Obteniendo lista generada al ejecutar SP
		@SuppressWarnings("unchecked")
		List<Usuario> listaUsuario= (List<Usuario>)data.get(LISTADO);
        
		// Declarando objeto usuario Obtenido
		Usuario usuarioObtenido = null;
		
		if (listaUsuario != null && listaUsuario.size()>0){
			// Obteniendo el primer elemento de la lista de usuario
			usuarioObtenido = listaUsuario.get(0);
			
			// Obteniendo lista de moduleso generada al ejecutar SP
			@SuppressWarnings("unchecked")
			List<Modulo> listaModulo = (List<Modulo>)data.get(LISTADO_MODULOS);
			
			// Declarando y instanciando objeto ListaModulo
			ListaModulo listaModuloResultado = new ListaModulo();
			// Agregando listaModulo al objeto listaModuloResultado;
			listaModuloResultado.setLista(listaModulo);
			
			// Obteniendo Rol del usuario
			Rol rol = usuarioObtenido.getRol();
			// Estableciendo modulos del rol
			rol.setListaModulo(listaModuloResultado);
			
			// Estableciendo el nuevo rol del usuario
			usuarioObtenido.setRol(rol);
		}
        
        if (logger.isDebugEnabled() && listaUsuario != null)
        {
            logger.debug("size=" + listaUsuario.size());
        }
        
		return usuarioObtenido;
	}
	
	@Override
	public ListaUsuario listarUsuario(Usuario usuario) {
		logger.info("listarUsuario");

		// Instanciando variable para llamado de SP
	    SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_LISTAR_USUARIO).
	    						  returningResultSet(LISTADO, new RowMapper<Usuario>(){
									@Override
									public Usuario mapRow(final ResultSet rs, final int numRow) throws SQLException
								    {
								        final Usuario usuario = new Usuario();
								        usuario.setCodUsuario(rs.getInt(CODUSUARIO));
								        usuario.setNombres(rs.getString(NOMBRES));
								        usuario.setApellidos(rs.getString(APELLIDOS));
								        usuario.setNombresyApellidos(rs.getString(NOMBRESYAPELLIDOS));
								        usuario.setNomUser(rs.getString(NOMUSER));
								        usuario.setPassUser(rs.getString(PASSUSER));
								        usuario.setEstado(rs.getString(ESTADO));
								        usuario.setEmail(rs.getString(EMAIL));
								        
								        Rol rol = new Rol();
								        rol.setCodigo(rs.getInt(ROL_CODROL));
								        rol.setDescripcion(rs.getString(ROL_DESCRIPCION));
								        
								        usuario.setRol(rol);
								        
								        usuario.setFechaRegistro(rs.getDate(FECHAREGISTRO).toString());
								        return usuario;
								    }
	    						  }
								);

	    // Estableciendo parametros de entrada al SP
	    SqlParameterSource parametros = new MapSqlParameterSource()
	    								.addValue(PARAM_NOMBRES, usuario.getNombres())
	    								.addValue(PARAM_APELLIDOS, usuario.getApellidos())
	    								.addValue(PARAM_CODROL, usuario.getRol()==null?null:usuario.getRol().getCodigo())
	    								.addValue(PARAM_ESTADO, usuario.getEstado()); 
        /*
	    Map<String, Object> parametros = new HashMap<String, Object>(2);
	    parametros.put(PARAM_CRITERIO, criterio);
	    parametros.put(PARAM_VALOR, valor);
	    */
	    // Establecer parametros y ejecutar SP
        Map<String,Object> data = llamarSP.execute(parametros);

        // Obteniendo lista generada de ejecutar SP
		@SuppressWarnings("unchecked")
		List<Usuario> listaUsuario= (List<Usuario>)data.get(LISTADO);
        
		// Instanciando objeto ListaUsuario
        ListaUsuario listaUsuarioResultado = new ListaUsuario();
        // Estableciendo resultado al objeto ListaUsuario
        listaUsuarioResultado.setLista(listaUsuario);
        
        if (logger.isDebugEnabled() && listaUsuarioResultado != null)
        {
            logger.debug("size=" + listaUsuarioResultado.size());
        }
        return listaUsuarioResultado;
	}

	@Override
	public Usuario obtenerUsuario(Usuario usuario) {
		logger.info("obtenerUsuario");
		
		// Instanciando variable para llamado de SP
	    SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_OBTENER_USUARIO).
								  returningResultSet(LISTADO, new RowMapper<Usuario>(){
									@Override
									public Usuario mapRow(final ResultSet rs, final int numRow) throws SQLException
								    {
								        final Usuario usuario = new Usuario();
								        usuario.setCodUsuario(rs.getInt(CODUSUARIO));
								        usuario.setNombres(rs.getString(NOMBRES));
								        usuario.setApellidos(rs.getString(APELLIDOS));
								        usuario.setNombresyApellidos(rs.getString(NOMBRESYAPELLIDOS));
								        usuario.setNomUser(rs.getString(NOMUSER));
								        usuario.setPassUser(rs.getString(PASSUSER));
								        usuario.setEstado(rs.getString(ESTADO));
								        usuario.setEmail(rs.getString(EMAIL));
								        
								        Rol rol = new Rol();
								        rol.setCodigo(rs.getInt(ROL_CODROL));
								        rol.setDescripcion(rs.getString(ROL_DESCRIPCION));
								        
								        usuario.setRol(rol);
								        
								        usuario.setFechaRegistro(rs.getDate(FECHAREGISTRO).toString());
								        return usuario;
								    }
								  }
								);

	    // Estableciendo parametros de entrada al SP
	    SqlParameterSource parametros = new MapSqlParameterSource()
	    								.addValue(PARAM_CODUSUARIO, usuario.getCodUsuario());

	    // Establecer parametros y ejecutar SP
        Map<String,Object> data = llamarSP.execute(parametros);

        // Obteniendo lista generada de ejecutar SP
		@SuppressWarnings("unchecked")
		List<Usuario> listaUsuario= (List<Usuario>)data.get(LISTADO);
        
		// Declarando objeto usuario Obtenido
		Usuario usuarioObtenido = null;
		
		if (listaUsuario != null && listaUsuario.size()>0){
			// Obteniendo el primer elemento de la lista de usuario
			usuarioObtenido = listaUsuario.get(0);
		}
        
        if (logger.isDebugEnabled() && listaUsuario != null)
        {
            logger.debug("size=" + listaUsuario.size());
        }
        
		return usuarioObtenido;
	}

	@Override
	public boolean registrarUsuario(Usuario usuario) {
		logger.info("registrarUsuario");
		
		// Instanciando variable para llamado de SP
	    SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_REGISTRAR_USUARIO);

	    // Estableciendo parametros de entrada al SP
	    SqlParameterSource parametros = new MapSqlParameterSource()
	    								.addValue(PARAM_NOMBRES, usuario.getNombres())
	    								.addValue(PARAM_APELLIDOS, usuario.getApellidos())
	    								.addValue(PARAM_NOMUSER, usuario.getNomUser())
	    								.addValue(PARAM_PASSUSER, usuario.getPassUser())
	    								.addValue(PARAM_ESTADO, usuario.getEstado())
	    								.addValue(PARAM_EMAIL, usuario.getEmail())
	    								.addValue(PARAM_CODROL, usuario.getRol().getCodigo());
	    
	    // Establecer parametros y ejecutar SP
	    Map<String,Object> data = llamarSP.execute(parametros);
	    
	    // Obteniendo el total de filas afectadas al ejecutar SP
	    int totalRegistrosAfectado = (Integer) data.get(TOTAL_FILAS_AFECTADAS);
	    
	    return totalRegistrosAfectado > 0;
	}

	@Override
	public boolean modificarUsuario(Usuario usuario) {
		logger.info("modificarUsuario");
		
		// Instanciando variable para llamado de SP
	    SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_MODIFICAR_USUARIO);

	    // Estableciendo parametros de entrada al SP
	    SqlParameterSource parametros = new MapSqlParameterSource()
	    								.addValue(PARAM_CODUSUARIO, usuario.getCodUsuario())
	    								.addValue(PARAM_NOMBRES, usuario.getNombres())
	    								.addValue(PARAM_APELLIDOS, usuario.getApellidos())
	    								.addValue(PARAM_NOMUSER, usuario.getNomUser())
	    								.addValue(PARAM_PASSUSER, usuario.getPassUser())
	    								.addValue(PARAM_ESTADO, usuario.getEstado())
	    								.addValue(PARAM_EMAIL, usuario.getEmail())
	    								.addValue(PARAM_CODROL, usuario.getRol().getCodigo());
	    
	    // Establecer parametros y ejecutar SP
	    Map<String,Object> data = llamarSP.execute(parametros);
	    
	    // Obteniendo el total de filas afectadas al ejecutar SP
	    int totalRegistrosAfectado = (Integer) data.get(TOTAL_FILAS_AFECTADAS);
	    
	    return totalRegistrosAfectado > 0;
	}

	@Override
	public boolean eliminarUsuario(Usuario usuario) {
		logger.info("eliminarUsuario");
		
		// Instanciando variable para llamado de SP
	    SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_ELIMINAR_USUARIO);

	    // Estableciendo parametros de entrada al SP
	    SqlParameterSource parametros = new MapSqlParameterSource()
	    								.addValue(PARAM_CODUSUARIO, usuario.getCodUsuario());
	    
	    // Establecer parametros y ejecutar SP
	    Map<String,Object> data = llamarSP.execute(parametros);
	    
	    // Obteniendo el total de filas afectadas al ejecutar SP
	    int totalRegistrosAfectado = (Integer) data.get(TOTAL_FILAS_AFECTADAS);
	    
	    return totalRegistrosAfectado > 0;
	}

	public ListaRol listarRol(){
		logger.info("listarRol");

		// Instanciando variable para llamado de SP
	    SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_LISTAR_ROL).
	    						  returningResultSet(LISTADO, new RowMapper<Rol>(){
									@Override
									public Rol mapRow(final ResultSet rs, final int numRow) throws SQLException
								    {
								        final Rol rol = new Rol();
								        rol.setCodigo(rs.getInt(ROL_CODROL));
								        rol.setDescripcion(rs.getString(ROL_DESCRIPCION));
								        rol.setEstado(rs.getString(ROL_ESTADO));
								        rol.setFechaRegistro(rs.getDate(FECHAREGISTRO).toString());
								        return rol;
								    }
	    						  }
								);

	    // Establecer parametros y ejecutar SP
        Map<String,Object> data = llamarSP.execute();

        // Obteniendo lista generada de ejecutar SP
		@SuppressWarnings("unchecked")
		List<Rol> listaRol= (List<Rol>)data.get(LISTADO);
        
		// Instanciando objeto ListaRol
        ListaRol listaRolResultado = new ListaRol();
        // Estableciendo resultado al objeto listaRolResultado
        listaRolResultado.setLista(listaRol);
        
        if (logger.isDebugEnabled() && listaRolResultado != null)
        {
            logger.debug("size=" + listaRolResultado.size());
        }
        return listaRolResultado;
	}
	
	public int validarRol(Usuario usuario, Modulo modulo){
		logger.info("validarRol");
		
		// Instanciando variable para llamado de SP
	    SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_CONSULTAR_ROL_MODULO)
	 				             .returningResultSet(LISTADO, new RowMapper<Usuario>() {
	 	          @Override
	 	          public Usuario mapRow(final ResultSet rs, final int numRow) throws SQLException {
	 						final Usuario usuario = new Usuario();
	 						usuario.setCodUsuario(rs.getInt(ROL_HABILITADO));
	 						
	 						return usuario;
	 	         }
	 		 				     });

	 		    // Estableciendo parametros de entrada al SP
	 		    SqlParameterSource parametros = new MapSqlParameterSource()
	 		    								.addValue(PARAM_CODROL, usuario.getRol().getCodigo())
	 		    								.addValue(PARAM_CODMODULO, modulo.getCodigo());
	 		    
	 		// Establecer parametros y ejecutar SP
		 		Map<String, Object> data = llamarSP.execute(parametros);

		 		// Obteniendo lista generada de ejecutar SP
		 		@SuppressWarnings("unchecked")
		 		List<Usuario> listaUsuario = (List<Usuario>) data.get(LISTADO);
		 		
		 	// Declarando objeto Guia Obtenido
		 		Usuario usuarioObtenido = null;

		 		if (logger.isDebugEnabled() && listaUsuario != null) {
		 			logger.debug("size=" + listaUsuario.size());
		 		}

		 		if (listaUsuario != null && listaUsuario.size() > 0) {
		 			// Obteniendo el primer elemento de la lista de Guia
		 			usuarioObtenido = listaUsuario.get(0);
		 		}
		 		
		    // Obteniendo el total de filas afectadas al ejecutar SP
		    int totalRegistrosAfectado = usuarioObtenido.getCodUsuario();
		        
		    return totalRegistrosAfectado;
	}          
	 						
}
